package org.pwwong.scalautils.property

import org.pwwong.scalautils.event._

import scala.collection.mutable.{Message,
                                 ObservableSet,
                                 HashSet => MutableSet,
                                 Subscriber}

import scala.collection.mutable.{Include,Remove,Reset}


object SetProp {
  
  case class SetPropEvent[T](val prop:SetProp[T])
  case class ClearEvent[T](_prop:SetProp[T]) extends SetPropEvent[T](_prop)
  class SetElementEvent[T](_prop:SetProp[T], val elem:T) extends SetPropEvent[T](_prop)
  case class AddEvent[T](_prop:SetProp[T], _elem:T) extends SetElementEvent[T](_prop, _elem)
  case class RemoveEvent[T](_prop:SetProp[T], _elem:T) extends SetElementEvent[T](_prop, _elem)
  
  class MutableSetImpl[T] extends MutableSet[T] with ObservableSet[T,MutableSetImpl[T]]
  class SetSubscriber[T](private val notifyFunc:(MutableSetImpl[T],Message[T])=>Unit) extends Subscriber[Message[T],MutableSetImpl[T]]{
    override def notify(a:MutableSetImpl[T],b:Message[T])=notifyFunc(a,b)
  }  
  def apply[T] = new SetProp[T]()
}

class SetProp[T] extends ChangeBroadcasting[SetProp.SetPropEvent[T]]{
  import SetProp._
  
  private[this] val set = new MutableSetImpl[T]
  private[this] val bufListener = new SetSubscriber[T](
    (a:MutableSetImpl[T],b:Message[T]) =>
	    b match {
            case include:Include[T] => onAdd.fire(AddEvent(this, include.elem))
		    case remove:Remove[T] => onRemove.fire(RemoveEvent(this, remove.elem))
		    case clear:Reset[_] => onClear.fire(ClearEvent(this))
	    }
  )
  private def fireChange(a:Any):Unit= onChange.fire(SetPropEvent(this))
  set.subscribe(bufListener);
  
  val onAdd = Event[AddEvent[T]](this){ fireChange }
  val onRemove = Event[RemoveEvent[T]](this){ fireChange }
  val onClear = Event[ClearEvent[T]](this){ fireChange }
  
  def apply():MutableSet[T] = set
}
